package com.yx.changdao.common.data;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yx.changdao.common.utils.ParseDictUtils;
import com.yx.changdao.common.utils.SysUtils;
import org.apache.commons.lang3.StringUtils;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Title: Result
 * @Description: 统一响应结果
 * @Auther: Zhangjiashun
 * @Version: 1.0
 * @create 2019/10/18 10:50
 */
public class Result extends NutMap {

    /**
     * 响应状态
     */
    public static final String RESP_CODE = "resp_code";
    public static final String RESP_MSG = "resp_msg";

    /**
     * 业务状态
     */
    public static final String RESULT_CODE = "result_code";
    public static final String RESULT_MSG = "result_msg";


    public static final String DATA = "data";
    public static final String PAGER = "pager";
    public static final String LIST = "list";
    private static final long serialVersionUID = 1335302556354189505L;


    private Result() {
        super();
    }

    public Result(RespCodeEnum respCode, ResultCodeEnum resultCode, Object data) {
        this(respCode, null, resultCode, null, data);
    }

    public Result(RespCodeEnum respCode, ResultCodeEnum resultCode) {
        this(respCode, null, resultCode, null, null);
    }

    public Result(RespCodeEnum respCode, String respMsg, ResultCodeEnum resultCode, String resultMsg, Object data) {
        this.put(RESP_CODE, respCode.getValue());
        if (StringUtils.isNotBlank(respMsg)) {
            this.put(RESP_MSG, respMsg);
        } else {
            this.put(RESP_MSG, respCode.getReasonPhrase());
        }
        this.put(RESULT_CODE, resultCode.getCode());
        if (StringUtils.isNotBlank(resultMsg)) {
            this.put(RESULT_MSG, resultMsg);
        } else {
            this.put(RESULT_MSG, resultCode.getMessage());
        }
        this.put(DATA, data);
    }


    /**
     * 成功结果
     *
     * @param resultMsg
     * @return
     */
    public static Result ok(String resultMsg) {
        return new Result(RespCodeEnum.OK, null, ResultCodeEnum.SUCCESS, resultMsg, null);
    }

    /**
     * 响应状态成功  业务状态自定义
     * @param resultMsg
     * @param resultCode
     * @return
     */
    public static Result ok(String resultMsg,ResultCodeEnum resultCode) {
        return new Result(RespCodeEnum.OK, null, resultCode, resultMsg, null);
    }
    public static Result ok() {
        return ok(null);
    }

    public static Result error() {
        return error(RespCodeEnum.INTERNAL_SERVER_ERROR, ResultCodeEnum.ERROR);
    }

    public static Result error(RespCodeEnum respCode, String msg) {
        return error(respCode, null, ResultCodeEnum.ERROR, msg);
    }

    public static Result error(RespCodeEnum respCode, ResultCodeEnum resultCode) {
        return error(respCode, null, resultCode, null);
    }

    public static Result error(RespCodeEnum respCode, String respMsg, ResultCodeEnum resultCode, String resultMsg) {
        return new Result(respCode, respMsg, resultCode, resultMsg, null);
    }

    public static Result error(String resultMsg) {
        return error(RespCodeEnum.INTERNAL_SERVER_ERROR, resultMsg);
    }


    public Result data(Object data, String... exclude) {
        this.put(DATA, excludeField(data, exclude));
        return this;
    }

    /**
     * 排除 data 的指定字段
     *
     * @param data
     * @param exclude 需要排除的属性
     */
    private static Object excludeField(Object data, String... exclude) {
        // 不需要排除原样返回。
        if (exclude == null) {
            return data;
        }

        Class<?> klass = data.getClass();
        // 如果该类继承自Map
        if (Map.class.isAssignableFrom(klass)) {
            Map map = (Map) data;

            // 如果是Map及其子类类型 覆盖相应属性
            for (String str : exclude) {
                // Map类型暂仅做简单单层，并未实现多层Map替换。
                // 将key刪除
                map.remove(str);
            }
            // 驼峰转下划线
            return humpMap2lineMap(map);

        }

        // 遍历需要排除的字段。
        for (String fieldName : exclude) {
            Field field = getFieldByName(klass, fieldName);
            if (field == null) {
                throw new IllegalArgumentException("字段" + fieldName + " 不存在");
            }

            field.setAccessible(true);
            // 将值赋值为null。
            try {
                field.set(data, null);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return data;
    }


    public Result data(String jsonData) {
        Object data = Json.fromJson(jsonData);
        return this.data(data);
    }

    /**
     * 解析分页结果集
     *
     * @param iPage   分页对象
     * @param exclude 排除字段
     * @return
     */
    public static <T> Result pagerList(IPage<T> iPage, String... exclude) {
        return pagerList(iPage, true, exclude);

    }

    /**
     * 解析分页结果集
     *
     * @param iPage       分页对象
     * @param toDictModel 是否开启字典映射
     * @param exclude     排除字段
     * @return
     */
    public static <T> Result pagerList(IPage<T> iPage, Boolean toDictModel, String... exclude) {
        List<T> records = iPage.getRecords();
        Map<String, Object> map = new HashMap<>();

        // 过滤列表内每一个条记录的字段。
        records.forEach(record -> excludeField(record, exclude));

        map.put(LIST, toDictModel ? ParseDictUtils.parseList(records) : records);
        map.put(PAGER, new Pager(iPage));


        return Result.ok().data(map);
    }


    /**
     * 根据类的属性名获取该属性，
     *
     * @param clazz
     * @param fieldName 可以是驼峰命名也可以是下划线命名
     * @return
     */
    private static Field getFieldByName(Class clazz, String fieldName) {
        Field field = null;
        List<String> fieldNames = new ArrayList<>();
        // 传入字符串
        fieldNames.add(fieldName);
        // 传入字符串如果是驼峰转化成下划线， 如果是下划线转化成驼峰。
        fieldNames.add(SysUtils.lineHumpInterconvert(fieldName));

        for (String name : fieldNames) {
            try {
                // 先判断类中是否有这个传入的属性 找到就返回。
                field = clazz.getDeclaredField(name);
                return field;
            } catch (NoSuchFieldException ignored) {
                // 对找不到属性的异常进行忽略。
            }
        }
        // 驼峰下划线都没找到说明没有这个字段。
        return null;
    }

    /**
     * 将驼峰map转化为下划线map
     *
     * @param humpMap
     * @return
     */
    private static <K, V> Map<String, V> humpMap2lineMap(Map<K, V> humpMap) {
        Map<String, V> lineMap = new LinkedHashMap<>();
        humpMap.keySet()
                .forEach(key -> lineMap.put(SysUtils.hump2Line(key.toString()), humpMap.get(key)));
        return lineMap;
    }
}
